/*  File Name	: DBMonitor.cpp
 *  Author		: Pang Jiacai
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-10-30
 *  Description:
 */

#include "DBMonitor.h"
#include "Reactor.h"
#include "EpollReactor.h"
#include "CommonStruct.h"

DBMonitor* DBMonitor::instance_ = NULL;

DBMonitor::DBMonitor()
{
	this->svc_unique_id_ = 0;
	this->server_map_.clear();
	this->account_map_.clear();
	this->load_succ_ = false;

	//this->init_db();
	//this->load_account(this->account_map_);
}

DBMonitor::~DBMonitor()
{

}

DBMonitor* DBMonitor::instance(void)
{
	if(instance_==NULL)
	{
		instance_ = new DBMonitor();
	}
	return instance_;
}

/*
 * id: befor login id mean svc_id,otherwise means roleid
 */
int DBMonitor::respond_succ_to_client(int id,int cmd,MessageBlock *mb)
{
	MessageBlock *mb_send = NULL;
	if(this->msg_pool()->pop(mb_send)==0)
	{
		*mb_send << id << cmd << 0 ;
		if(NULL!=mb)
		{
			mb_send->write(mb->rd_ptr(),mb->data_len());
		}
		this->respond_mb_push(mb_send);
	}
	return 0;
}

/*
 * id: before login id mean svc_id,otherwise means roleid
 */
int DBMonitor::respond_error_to_client(int id,int cmd,int error,MessageBlock *mb)
{
	MessageBlock *mb_send = NULL;
	if(this->msg_pool()->pop(mb_send)==0)
	{
		*mb_send << id << cmd << error;
		if(NULL!=mb)
		{
			mb_send->write(mb->rd_ptr(),mb->data_len());
		}
		this->respond_mb_push(mb_send);
	}
	return 0;
}

int DBMonitor::init(int line_id,int list_size,int block_size,int pool_size,
		int growth_size,std::string pool_name)
{
	if(NULL==this->local_db())
	{
		LOG((ERROR_LOG,"DBMonitor::init-->error can't connect db [%d]",line_id));
		sleep(1);
		return -1;
	}

	super::init(list_size,block_size,pool_size,growth_size,pool_name);

	this->acceptor_ = new DBServerAcceptor(this);
	if(NULL==this->acceptor_)
	{
		return -1;
	}

	//request thread
	int req_thr = this->cfg()["request_thr"].asInt();
	this->create_request_thr(req_thr,"DBMonitor::request",false);

	//respond thread
	int res_thr = this->cfg()["respond_thr"].asInt();
	this->create_respond_thr(res_thr,"DBMonitor::respond",false);

	this->reactor(Reactor::instance());
	if(NULL==this->reactor()->implement())
	{
		this->reactor()->implement(new EpollReactor(10000,102400));
	}
	return 0;
}

const Json::Value &DBMonitor::cfg(void)
{
#ifdef DEBUG
	return CONFIG_INSTANCE->dbserver()["debug"][0u];

#else
	return CONFIG_INSTANCE->dbserver()["online"][0u];
#endif
}

int DBMonitor::start(void)
{
	super::start();

	int port = this->cfg()["port"].asInt();

	if(this->acceptor_->open(port,this->reactor())!=0)
	{
		return -1;
	}
#ifndef DEBUG
	this->reactor()->run_reactor_loop();
	this->wait_thread_exit();
#endif
	return 0;
}

int DBMonitor::stop(void)
{
	return this->reactor()->end_reactor_loop();
}

int DBMonitor::run_request_loop(void)
{
	while(true)
	{
		if(this->reactor()->run_status()==2)
		{
			LOG((INFO_LOG,"DBMonitor::run_request_loop exit"));
			return 0;
		}

		MessageBlock *mb = NULL;
		this->request_mb_pop(mb);
		if (NULL != mb)
		{
			this->process_request(mb);
			this->msg_pool()->push(mb);
		}
		else
		{
			usleep(1000);
		}
	}
	return 0;
}

int DBMonitor::run_respond_loop(void)
{
	while(true)
	{
		if(this->reactor()->run_status()==2)
		{
			LOG((INFO_LOG,"DBMonitor::run_respond_loop exit"));
			return 0;
		}

		MessageBlock *mb = NULL;
		this->respond_mb_pop(mb);
		if(NULL!=mb)
		{
			this->process_respond(mb);
			this->msg_pool()->push(mb);
		}
		else
		{
			usleep(1000);
		}
	}
	return 0;
}


int DBMonitor::process_respond(MessageBlock *mb)
{
	int svc_id =0,cmd =0;
	*mb >> svc_id>>cmd;

	DBService *dbs = this->find_service(svc_id);
	int send_len =0;
	if (NULL != dbs)
	{
		int len = mb->data_len();
		mb->reset_rd_ptr();
		::memcpy(mb->base_ptr(), (char*) &len, sizeof(int));
		send_len = dbs->send_msg(mb, mb->data_len());
	}
	LOG((DEBUG_LOG,"DBMonitor::process_respond-->[cmd:%d][svc:%d][send:%d]",
					cmd,svc_id,send_len));
	return 0;
}

int DBMonitor::process_request(MessageBlock *mb)
{
	int svc_id = 0, cmd = 0,remain=0;
	*mb >> svc_id >>cmd >> remain;

	DBService *gs = this->find_service(svc_id);
	if (NULL==gs)
	{
		LOG((ERROR_LOG,"DBMonitor::process_request-->can't find svc"));
		return -1;
	}
	LOG((INFO_LOG,"DBMonitor::process_request-->[cmd:%d][svc:%d][from:%s:%d]",
			cmd,svc_id,gs->peer_addr(),gs->peer_port()));

	switch(cmd)
	{
		case DBSERVER_WEB_CREATE_ACCOUNT:
		{
			return this->web_create_account(svc_id,mb);
		}
		case DBSERVER_WEB_LOGIN:
		{
			return this->web_login(svc_id,mb);
		}
		case DBSERVER_WEB_LOGOUT:
		{
			return this->web_logout(svc_id,mb);
		}
		case DBSERVER_PLAYER_LOGIN:
		{
			return this->player_login(svc_id,mb);
		}
		default:
		{
			return 0;
		}
	}
	return 0;
}

